package com.unsins.core.service.hibernate;

import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;

import com.unsins.core.exception.ObjectNotFoundException;
import com.unsins.core.service.IBaseService;

/**
 * 以hibernate方式实现IBaseService的接口
 * 
 * @author odpsoft
 * @create time: 2008-10-30
 */
public class BaseServiceHibernateImpl extends HibernateDaoSupport implements IBaseService {
	protected final Logger logger = Logger.getLogger(this.getClass());

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#findBy(java.lang.Class,
	 *      java.lang.String, java.lang.Object)
	 */
	public List findBy(Class clazz, String propertyName, Object propertyValue) {
		Assert.hasText(propertyName);
		Session session = this.getSessionFactory().getCurrentSession();
		Criteria criteria = session.createCriteria(clazz);
		criteria.add(Restrictions.eq(propertyName, propertyValue));

		return criteria.list();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#findBy(java.lang.Class,
	 *      java.lang.String, java.lang.Object, java.lang.String, boolean)
	 */
	public List findBy(Class clazz, String propertyName, Object propertyValue, String orderBy, boolean isAsc) {
		Assert.hasText(propertyName);
		Assert.hasText(orderBy);
		Session session = this.getSessionFactory().getCurrentSession();
		Criteria criteria = session.createCriteria(clazz);
		criteria.add(Restrictions.eq(propertyName, propertyValue));

		if (isAsc) {
			criteria.addOrder(Order.asc(orderBy));
		} else {
			criteria.addOrder(Order.desc(orderBy));
		}

		return criteria.list();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#findUniqueBy(java.lang.Class,
	 *      java.lang.String, java.lang.Object)
	 */
	public Object findUniqueBy(Class clazz, String propertyName, Object propertyValue) {
		Assert.hasText(propertyName);
		Session session = this.getSessionFactory().getCurrentSession();
		Criteria criteria = session.createCriteria(clazz);
		criteria.add(Restrictions.eq(propertyName, propertyValue));

		return criteria.uniqueResult();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#getDomainEntity(java.lang.Class,
	 *      java.io.Serializable)
	 */
	public Object getDomainEntity(Class clazz, Serializable id) throws ObjectNotFoundException {
		return this.getHibernateTemplate().get(clazz, id);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#loadDomainEntity(java.lang.Class,
	 *      java.io.Serializable)
	 */
	public Object loadDomainEntity(Class clazz, Serializable id) throws ObjectNotFoundException {
		return this.getHibernateTemplate().load(clazz, id);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#removeDomainEntity(java.lang.Class,
	 *      java.io.Serializable)
	 */
	public void removeDomainEntity(Object clazz) throws DataAccessException {
		this.getHibernateTemplate().delete(clazz);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#saveDomainEntity(java.lang.Object)
	 */
	public Serializable saveDomainEntity(Object object) throws DataAccessException {
		return this.getHibernateTemplate().save(object);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#updateDomainEntity(java.lang.Class)
	 */
	public void updateDomainEntity(Object clazz) throws DataAccessException {
		this.getHibernateTemplate().update(clazz);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#removeDomainEntityById(java.lang.Class,
	 *      java.io.Serializable)
	 */
	public void removeDomainEntityById(Class clazz, Serializable id) throws DataAccessException {
		this.removeDomainEntity(getDomainEntity(clazz, id));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#findAllByMapKey(java.lang.Class,
	 *      java.util.Map)
	 */
	public List findAllByMapKey(Class clazz, Map keyMap) {
		StringBuffer buffer = new StringBuffer("from ");
		buffer.append(getTableNameFromClass(clazz));
		buffer.append(" where ");
		List keys = new LinkedList(keyMap.keySet());
		Object[] values = new String[keys.size()];
		int i = 0;

		for (int k = 0; k < keys.size(); k++) {
			buffer.append(keys.get(k).toString());
			buffer.append("=? and ");
			values[k] = keyMap.get(keys.get(k));
			i = k;
		}

		String hql = buffer.toString();
		if (i > 0) {
			String temp = buffer.toString();
			hql = temp.substring(0, buffer.toString().lastIndexOf("and"));
		}

		if (logger.isDebugEnabled())
			logger.debug(hql);
		
		return this.getHibernateTemplate().find(hql, values);
	}

	private String getTableNameFromClass(Class entity) {
		String className = entity.getName();
		
		return className.substring(className.lastIndexOf(".") + 1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.unsins.core.service.IBaseService#findAllByHQL(java.lang.String)
	 */
	public List findAllByHQL(String hql) {
		if (logger.isDebugEnabled())
			logger.debug(hql);

		return this.getHibernateTemplate().find(hql);
	}
	
	protected List findByCriteria(Class clazz,Criterion[] criterion){
		Session session = this.getSessionFactory().getCurrentSession();
		Criteria criteria = session.createCriteria(clazz);
		
		for(int i=0;i<criterion.length;i++){
			criteria.add(criterion[i]);
		}
		
		return criteria.list();
	}

	/* (non-Javadoc)
	 * @see com.unsins.core.service.IBaseService#findAll(java.lang.Class)
	 */
	public List findAll(Class clazz) {
		return findByCriteria(clazz,new Criterion[]{});
	}

}
